package xiaojian.toolkit.netty.handler.codec.http.response;

import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.handler.codec.http.*;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;

/**
 * @author hp
 */
public class NettyHttpResponseSender implements HttpResponseSender {
	private boolean keepAlive;

	public void sendResponse(Channel channel, HttpResponse response) {
		ChannelFuture future = channel.writeAndFlush(response);
		if (!keepAlive
				|| !HttpHeaders.isKeepAlive(response)
				|| !response.headers().contains(
						HttpHeaders.Names.CONTENT_LENGTH)) {
			// no content
			future.addListener(ChannelFutureListener.CLOSE);
		}
	}

	public void sendResponse(Channel channel,
			HttpResponseStatus httpResponseStatus, String responseContent)
			throws UnsupportedEncodingException {
		sendResponse(channel, httpResponseStatus, responseContent, "UTF-8");
	}

	public void sendResponse(Channel channel,
			HttpResponseStatus httpResponseStatus, String responseContent,
			String charsetName) throws UnsupportedEncodingException {
		FullHttpResponse response = new DefaultFullHttpResponse(
				HttpVersion.HTTP_1_1, httpResponseStatus);
		byte[] contents = responseContent.getBytes(charsetName);
		response.content().writeBytes(Unpooled.wrappedBuffer(contents));
		response.headers().set(HttpHeaders.Names.CONTENT_LENGTH,
				contents.length);
		sendResponse(channel, response);
	}

	/**
	 * send file to the remote http client,give us the <b>full content</b> and
	 * range,we will cut the content to partial
	 * 
	 * @param channel
	 *            {@link io.netty.channel.Channel}
	 * @param fullContent
	 *            the full content without any range information
	 * @param startPos
	 *            the start position of content,<b>inclusive</b>,set 0 to ignore
	 *            startPos
	 * @param endPos
	 *            the end position of content,<b>inclusive</b>,set 0 to ignore
	 *            endPos
	 * @return the Content-Range String,null if not a Partial Content response
	 */
	public String sendFile(Channel channel, byte[] fullContent, int startPos,
			int endPos) {
		HttpResponseStatus httpResponseStatus = (startPos > 0 || endPos > 0) ? HttpResponseStatus.PARTIAL_CONTENT
				: HttpResponseStatus.OK;
		if (startPos < 0 || startPos > fullContent.length)
			startPos = 0;
		if (endPos < startPos || endPos > fullContent.length || endPos <= 0)
			endPos = fullContent.length - 1;

		FullHttpResponse response = new DefaultFullHttpResponse(
				HttpVersion.HTTP_1_1, httpResponseStatus);
		byte[] partialContent = Arrays.copyOfRange(fullContent, startPos,
				endPos + 1);
		response.content().writeBytes(Unpooled.wrappedBuffer(partialContent));
		response.headers().set(HttpHeaders.Names.CONTENT_LENGTH,
				partialContent.length);
		String range = "bytes " + startPos + "-" + endPos + "/"
				+ fullContent.length;
		if (httpResponseStatus.equals(HttpResponseStatus.PARTIAL_CONTENT)) {
			response.headers().set(HttpHeaders.Names.CONTENT_RANGE, range);
		}
		sendResponse(channel, response);

		return httpResponseStatus.equals(HttpResponseStatus.PARTIAL_CONTENT) ? range
				: null;
	}

	public void sendNotFoundResponse(Channel channel) {
		HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1,
				HttpResponseStatus.NOT_FOUND);
		sendResponse(channel, response);
	}

	public void sendGatewayTimeoutResponse(Channel channel) {
		HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1,
				HttpResponseStatus.GATEWAY_TIMEOUT);
		sendResponse(channel, response);
	}

	public void sendRedirectResponse(Channel channel, String redirectUrl) {
		HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1,
				HttpResponseStatus.TEMPORARY_REDIRECT);
		response.headers().set(HttpHeaders.Names.LOCATION, redirectUrl);
		sendResponse(channel, response);
	}

	public void setKeepAlive(boolean keepAlive) {
		this.keepAlive = keepAlive;
	}

	public boolean isKeepAlive() {
		return keepAlive;
	}
}
